// Copyright 2011 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.

/*
The mail package provides the means of sending email from an
App Engine application.

Example:
	msg := &mail.Message{
		Sender:  "romeo@montague.com",
		To:      []string{"Juliet <juliet@capulet.org>"},
		Subject: "See you tonight",
		Body:    "Don't forget our plans. Hark, 'til later.",
	}
	if err := mail.Send(c, msg); err != nil {
		c.Logf("Alas, my user, the email failed to sendeth: %v", err)
	}
*/
package mail

import (
	"os"
	"log"
//    "template"
    "fmt"
	"strings"
	"bufio"
	"mime"
	"mime/multipart"
	//"mail"
	"net/textproto"
	"io/ioutil"
	"io"
	//"bytes"
	//"regexp"
	"encoding/base64"
	"appengine"
	mail_proto "appengine_internal/mail"
)

var logger = log.New(os.Stderr, "", log.Lshortfile)



/* --------------------------------------------------------------------------------------- */




/*
type Mail struct {
	content []byte
	tp *textproto.Reader
	header map[string][]string
	mpr multipart.Reader
}
*/
type Mail struct {
	Sender  string
	ReplyTo string // may be empty

	To, Cc, Bcc []string

	Subject string
	TextBody    string
	HtmlBody    string

	header  textproto.MIMEHeader
	content []byte
}

func NewMail( in io.Reader) (mail *Mail, err os.Error) {
  	mail = new(Mail)
 
 	mail.content, err = ioutil.ReadAll( in)
    if err != nil {
        return nil, err
  	}
  	//re := regexp.MustCompile( "[^\r]\n") 
  	//res := re.FindAll( mail.content, -1)
  	//fmt.Printf( "%v\n", res)

  	//mail.content = re.ReplaceAll( mail.content, ([]uint8)("\r\n"))
  	b := NewMyReader( mail.content)
	b2 := bufio.NewReader( b)
	tp := textproto.NewReader(b2)
//	mail.tp = textproto.NewReader(b2)
	fmt.Printf("readedMime, %v\n",err)
  	
  	//fmt.Println( string(content))
 	mail.header, err = tp.ReadMIMEHeader()

  	mail.Sender = mail.header["From"][0]
  	mail.ReplyTo = mail.header["Return-Path"][0]
  	mail.To = mail.header["To"]
  	mail.Cc = mail.header["Cc"]
  	mail.Bcc = mail.header["Bcc"]
  	
  	mail.Subject = mail.header["Subject"][0]
  	
	contentType, params := mime.ParseMediaType( mail.Header("Content-Type")[0])
	log.Printf( "* contentType=%v", contentType)
	switch contentType {
		case "multipart/alternative":
			boundary := params["boundary"]
			log.Printf( "* boundary=%v", boundary)
			mpr := multipart.NewReader( tp.R, boundary)
			for {
				part, err := mpr.NextPart()
				if err != nil {
					return
				}
				if part == nil {
					break
				}
				headers, body, err := readPart(part)
//				log.Printf( "* 1headers=%v", headers.Get( "Content-Type"))
//				log.Printf( "* 1headers=%v", headers.Get( "Content-Transfer-Encoding"))
				_ = headers
				_ = body
				contentType, params := mime.ParseMediaType( headers.Get( "Content-Type"))
			log.Printf( "* transfer-encoding=%v", mail.header.Get( "Content-Transfer-Encoding"))
				log.Printf( "* contentType=%v", contentType)
				log.Printf( "* params=%v", params)
				//log.Printf( "* body=%v", string(body))
				switch contentType {
					case "text/plain":
						mail.TextBody = string(body)
					case "text/html":
						mail.HtmlBody = string(body)
				}
			}			

		case "text/plain":
			logger.Printf( "* params=%v", params)
			logger.Printf( "* transfer-encoding=%v", mail.header.Get( "Content-Transfer-Encoding"))
//body, err := ioutil.ReadAll( tp.R)
//logger.Printf( "* body=%v", string(body))
			mail.TextBody, err = decode( mail.header.Get( "Content-Transfer-Encoding"), tp.R)
			if err != nil {
				logger.Fatalf( "Decoding error:%v", err)
			}
			//_ = err
			
		case "text/html":
			body, err := ioutil.ReadAll( tp.R)
			mail.TextBody = string(body)
			_ = err
			
		default:
			body, err := ioutil.ReadAll( tp.R)
			mail.TextBody = string(body)
			_ = err
	}
	return
}
/*
func (mail *Mail) NewReader( ) io.Reader {
	return bytes.NewBuffer( mail.content)	
}
*/
func (mail *Mail) Header( key string) []string {
//	if mail.tp == nil {
//		mail.readMime()
//	}
	return mail.header[key]
}

func (mail *Mail) Content( ) []byte {
	return mail.content
}


/*
func (mail *Mail) MediaType( ) (mediatype string, params map[string]string) {
	v := mail.Header("Content-Type")[0]
	return mime.ParseMediaType(v)
}
*/
func decode( contentTransferEncoding string, body io.Reader) (decodedBody string, err os.Error){
//	partBody, err := ioutil.ReadAll( body)
//	logger.Printf( "partBody-base64:<<%v>>", string(partBody))

	switch contentTransferEncoding {
		case "base64":
			body2 := NewReaderWithoutCRLF( body)
			if err != nil {
				return "", err
			}
			decoded := base64.NewDecoder( base64.StdEncoding, body2)
			decodedBodyAux, err := ioutil.ReadAll( decoded)
			if err != nil {
				logger.Printf( "Error %v-%v", string(decodedBodyAux), err)
				return
			}
	//logger.Printf( "decoding... %v", decodedBodyAux)
			//decodedBody = string(decodedBodyAux)
			//logger.Printf( "partBody-base64:<<%v>>", string(decodedBodyAux))
			str2 := string(decodedBodyAux)
			str2 = strings.Replace(str2, "\xE7", "ç", -1)
			str2 = strings.Replace(str2, "\xF1", "ñ", -1)
			str2 = strings.Replace(str2, "\xE1", "á", -1)
			str2 = strings.Replace(str2, "\xE9", "é", -1)
			str2 = strings.Replace(str2, "\xED", "í", -1)
			str2 = strings.Replace(str2, "\xF3", "ó", -1)
			str2 = strings.Replace(str2, "\xFA", "ú", -1)
			str2 = strings.Replace(str2, "\xD1", "Ñ", -1)
			str2 = strings.Replace(str2, "\xC7", "Ç", -1)
			str2 = strings.Replace(str2, "\xC1", "Á", -1)
			str2 = strings.Replace(str2, "\xC9", "É", -1)
			str2 = strings.Replace(str2, "\xCD", "Í", -1)
			str2 = strings.Replace(str2, "\xD3", "Ó", -1)
			str2 = strings.Replace(str2, "\xDA", "Ú", -1) 
			decodedBody = str2
//	logger.Printf( "decoding... %v", decodedBody)
	}	
	return
}


func readPart( part *multipart.Part) (partHeader *textproto.MIMEHeader, partBody []byte, err os.Error) {
	partHeader = &part.Header

	if partHeader.Get("Content-Transfer-Encoding") == "base64" {
		r := NewDecoder( StdEncoding, part) 
		partBody, err = ioutil.ReadAll( r)
//		logger.Printf( "partBody-base64:<<%v>>", string(partBody))
		str2 := string(partBody)
		str2 = strings.Replace(str2, "\xE7", "ç", -1)
		str2 = strings.Replace(str2, "\xF1", "ñ", -1)
		str2 = strings.Replace(str2, "\xE1", "á", -1)
		str2 = strings.Replace(str2, "\xE9", "é", -1)
		str2 = strings.Replace(str2, "\xED", "í", -1)
		str2 = strings.Replace(str2, "\xF3", "ó", -1)
		str2 = strings.Replace(str2, "\xFA", "ú", -1)
		str2 = strings.Replace(str2, "\xD1", "Ñ", -1)
		str2 = strings.Replace(str2, "\xC7", "Ç", -1)
		str2 = strings.Replace(str2, "\xC1", "Á", -1)
		str2 = strings.Replace(str2, "\xC9", "É", -1)
		str2 = strings.Replace(str2, "\xCD", "Í", -1)
		str2 = strings.Replace(str2, "\xD3", "Ó", -1)
		str2 = strings.Replace(str2, "\xDA", "Ú", -1) 
		partBody = []uint8(str2)
		return
	}	
	partBody, err = ioutil.ReadAll( part)
//	logger.Printf( "partBody-text:<<%v>>", string(partBody))
	body := string(partBody)
	body = strings.Replace( body, "=E1", "á", -1)
	body = strings.Replace( body, "=E9", "é", -1)
	body = strings.Replace( body, "=ED", "í", -1)
	body = strings.Replace( body, "=F3", "ó", -1)
	body = strings.Replace( body, "=F3", "ú", -1)
	body = strings.Replace( body, "=F1", "ñ", -1)

	body = strings.Replace(body, "=D1", "Ñ", -1)
	body = strings.Replace(body, "=C7", "Ç", -1)
	body = strings.Replace(body, "=C1", "Á", -1)
	body = strings.Replace(body, "=C9", "É", -1)
	body = strings.Replace(body, "=CD", "Í", -1)
	body = strings.Replace(body, "=D3", "Ó", -1)
	body = strings.Replace(body, "=DA", "Ú", -1) 
	partBody = []uint8(body)
	return
}



func SendMail( c appengine.Context, mail *Mail) os.Error {
 	c.Debugf( "From:<<%v>>", mail.Header("From"))
	c.Debugf( "To:<<%v>>", mail.Header("To"))
	c.Debugf( "Subject:<<%v>>", mail.Header("Subject"))

	req := &mail_proto.MailMessage{
		Sender:   &mail.Sender,
		To:       mail.To,
		Cc:       mail.Cc,
		Bcc:      mail.Bcc,
		Subject:  &mail.Subject,
		TextBody: &mail.TextBody,
		HtmlBody: &mail.HtmlBody,
	}
	if mail.ReplyTo != "" {
		req.ReplyTo = &mail.ReplyTo
	}
	res := &struct{}{} // VoidProto
	if err := c.Call("mail", "Send", req, res); err != nil {
		return err
	}
    c.Debugf("Mail sended to '" + mail.Header("From")[0] + "'")
	return nil
}
